package com.joysuch.wwyt.workflow.task;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.joysuch.wwyt.bp.constant.AppNotifyContentPre;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.common.entity.CommonBusinessNotice;
import com.joysuch.wwyt.common.entity.CommonIndexNotify;
import com.joysuch.wwyt.common.enums.AppBusinessNoticeTypes;
import com.joysuch.wwyt.common.enums.CommonIndexNotifyTypes;
import com.joysuch.wwyt.common.repository.CommonIndexNotifyDao;
import com.joysuch.wwyt.common.service.CommonBusinessNoticeService;
import com.joysuch.wwyt.common.service.CommonIndexNotifyService;
import com.joysuch.wwyt.core.bean.BpUserListBean;
import com.joysuch.wwyt.core.entity.BaseConfig;
import com.joysuch.wwyt.core.service.BaseConfigService;
import com.joysuch.wwyt.core.service.BaseUserService;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.edu.mapper.WwytBpDepartMapper;
import com.joysuch.wwyt.workflow.entity.WorkFlowProcess;
import com.joysuch.wwyt.workflow.entity.dto.WorkflowTaskDto;
import com.joysuch.wwyt.workflow.mapper.WorkflowTaskMapper;
import com.joysuch.wwyt.workflow.repository.WorkFlowProcessDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoq
 * 2022-06-13
 */
@Slf4j
@Component
public class WorkflowExpireNoticeTask {

    @Resource
    private WorkFlowProcessDao processDao;
    @Resource
    private BaseConfigService baseConfigService;
    @Resource
    private WorkflowTaskMapper workflowTaskMapper;
    @Resource
    private WwytBpDepartMapper departMapper;
    @Resource
    private BaseUserService userService;
    @Resource
    private CommonIndexNotifyDao commonIndexNotifyDao;
    @Resource
    private CommonIndexNotifyService commonIndexNotifyService;
    @Resource
    private CommonBusinessNoticeService commonBusinessNoticeService;

    @Scheduled(cron = "0 20 2 * * *")
    public void expireNoticeTask() {
        try {
            List<WorkFlowProcess> allProcess = processDao.findAll();

            for (WorkFlowProcess process : allProcess) {
                try {
                    String bizName = process.getBizName();
                    String configKey = bizName + ".临过期";
                    BaseConfig config = baseConfigService.findConfig(Context.getCurrentTenantId(), Context.getCompanyCode(), configKey);
                    if (config == null || Strings.isNullOrEmpty(config.getValue())) {
                        continue;
                    }
                    String configVal = config.getValue().trim();
                    String[] fields = configVal.split(",");

                    JSONObject srcLabelKey = JSONObject.parseObject(process.getFormKeyLabelJson());
                    JSONObject formJson = JSONObject.parseObject(process.getFormJson());
                    for (String field : fields) {
                        String[] labelDaysUserOrDepartFormat = field.split("\\|");
                        String fieldLabel = labelDaysUserOrDepartFormat[0];
                        String userOrDepartLabel = labelDaysUserOrDepartFormat[2];
                        String userOrDepartKey = srcLabelKey.getString(userOrDepartLabel);
                        String dateFormat = labelDaysUserOrDepartFormat[3];
                        String infoLabel = labelDaysUserOrDepartFormat[4];
                        String infoKey = srcLabelKey.getString(infoLabel);

                        String fieldKey = srcLabelKey.getString(fieldLabel);
                        if (Strings.isNullOrEmpty(fieldKey)) {
                            continue;
                        }
                        if (Strings.isNullOrEmpty(userOrDepartKey)) {
                            continue;
                        }
                        if (Strings.isNullOrEmpty(infoLabel)) {
                            continue;
                        }
                        if (Strings.isNullOrEmpty(infoKey)) {
                            continue;
                        }
                        String diaType = null;
                        JSONArray temArr = formJson.getJSONArray("temArr");
                        for (int idx = 0; idx < temArr.size(); idx++) {
                            JSONObject module = temArr.getJSONObject(idx);
                            JSONArray tableArr = module.getJSONArray("tableArr");
                            for (int it = 0; it < tableArr.size(); it++) {
                                JSONObject fieldDesc = tableArr.getJSONObject(it);
                                if (fieldDesc.getString("key").equals(userOrDepartKey)) {
                                    diaType = fieldDesc.getString("diaType");
                                    break;
                                }
                            }
                        }
                        if (Strings.isNullOrEmpty(diaType)) {
                            continue;
                        }

                        List<Integer> days = Arrays.stream(labelDaysUserOrDepartFormat[1].split("\\."))
                                .map(Integer::parseInt)
                                .collect(Collectors.toList());
                        if (days.size() == 0) {
                            continue;
                        }
                        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(dateFormat);
                        String companyCode = Context.getCompanyCode();
                        Long tenantId = Context.getCurrentTenantId();
                        for (Integer day : days) {
                            String checkDay = LocalDateTime.now().plusDays(day).format(dtf);
                            Page<WorkflowTaskDto> page = new Page<>(1, 1000);
                            IPage<WorkflowTaskDto> tasks = workflowTaskMapper.queryAllTaskPaging(page, Arrays.asList(process.getId()), null,
                                    " and JSON_EXTRACT(form_data, '$." + fieldKey + "') = '" + checkDay + "' ",
                                    null, companyCode, tenantId, null);
                            if (tasks.getRecords().size() > 0) {
                                for (WorkflowTaskDto task : tasks.getRecords()) {
                                    try {
                                        JSONObject formData = JSONObject.parseObject(task.getFormData());
                                        JSONObject objectId = JSONObject.parseObject(task.getObjectId());
                                        JSONArray userOrDeparts = objectId.getJSONArray(userOrDepartKey);
                                        if (userOrDeparts != null && userOrDeparts.size() > 0) {
                                            List<Long> ids = new ArrayList<>();
                                            for (int udIdx = 0; udIdx < userOrDeparts.size(); udIdx++) {
                                                Long id = userOrDeparts.getJSONObject(udIdx).getLong("id");
                                                if (id != null) {
                                                    ids.add(id);
                                                }
                                            }
                                            List<Long> userIds = new ArrayList<>();
                                            if ("person".equals(diaType)) {
                                                userIds.addAll(ids);
                                            }
                                            if ("department".equals(diaType)) {
                                                userIds.addAll(ids.stream()
                                                        .map(departMapper::selectById)
                                                        .filter(Objects::nonNull)
                                                        .map(BpDepart::getChiefId)
                                                        .filter(Objects::nonNull)
                                                        .collect(Collectors.toList()));
                                            }
                                            if (userIds.size() > 0) {
                                                String infoVal = formData.getString(infoKey);
                                                StringBuilder notice = new StringBuilder();
                                                notice.append(process.getBizName());
                                                if (!Strings.isNullOrEmpty(infoVal)) {
                                                    notice.append("[" + infoVal + "]");
                                                }
                                                notice.append("即将在")
                                                        .append(day)
                                                        .append("天后的")
                                                        .append(checkDay)
                                                        .append("到期，请您及时处理。");

                                                _sendNotice(userIds, notice.toString(), task.getId());
                                            }
                                        }
                                    } catch (Exception e) {
                                        log.error("执行流程引擎" + process.getBizName() + "过期提醒异常，bizTaskId:" + task.getId(), e);
                                    }
                                }
                            }
                        }
                    }

                } catch (Exception e) {
                    log.error("执行流程引擎" + process.getBizName() + "过期提醒异常", e);
                }
            }
        } catch (Exception e) {
            log.error("执行流程引擎过期提醒异常", e);
        }
    }

    private void _sendNotice(List<Long> userIds, String content, Long bizTaskId) {

        List<CommonIndexNotify> notifyList = Lists.newArrayList();

        Date now = new Date();
        List<CommonBusinessNotice> commonBusinessNotices = Lists.newArrayList();
        for (Long userId : userIds) {
            BpUserListBean baseUser = userService.findById(userId);
            CommonIndexNotify notify = new CommonIndexNotify();
            //到期提醒日期
            notify.setRemindDate(LocalDate.now());
            //到期提醒时间
            notify.setRemindDateTime(LocalDateTime.now());

            notify.setType(CommonIndexNotifyTypes.DOC_EXPIRE.getType());
            notify.setReadFlag(0);
            notify.setQueueOrNot(0);
            notify.setRemindedOrNot(0);
            //到期提醒日期
            notify.setRemindDate(LocalDate.now());
            //到期提醒时间
            notify.setRemindDateTime(LocalDateTime.now());
            //人员id
            notify.setUserId(baseUser.getId());
            String message = content;
            notify.setTenentId(baseUser.getTenentId());
            notify.setOrgCode(baseUser.getOrgCode());
            notify.setCreateBy(null);
            notify.setUpdateBy(null);
            notify.setReadFlag(0);
            notify.setQueueOrNot(1);
            notify.setRemindedOrNot(1);
            notify.setEduCertUserId(baseUser.getId());
            notify.setNotifyMessage(message);

            notifyList.add(notify);

            CommonBusinessNotice notice = new CommonBusinessNotice();
            notice.setNoticeTitle(AppNotifyContentPre.TASK_WILL_TIME_OUT_NOTIFY);
            notice.setBusinessType(AppBusinessNoticeTypes.CERT_MATURITY.getType());
            notice.setNoticeContent(message);
            notice.setNoticeUser(baseUser.getId());
            notice.setReaded("0");
            notice.setRefId(bizTaskId);
            notice.setSendTime(new Date());

            notice.setTenentId(baseUser.getTenentId());
            notice.setOrgCode(baseUser.getOrgCode());
            notice.setCreateBy(baseUser.getId());
            notice.setUpdateBy(baseUser.getId());

            notice.setCreateTime(now);
            notice.setUpdateTime(now);
            notice.setDeleteFlag("0");

            commonBusinessNotices.add(notice);
        }

        if (notifyList.size() > 0) {
            commonIndexNotifyDao.saveAll(notifyList);
            commonIndexNotifyService.getNotify();
        }

        if (commonBusinessNotices.size() > 0) {
            // app消息中心
            commonBusinessNoticeService.saveBatch(commonBusinessNotices);
        }
    }

}
